// i_state_init : load data 
// i_state_calc : calculating



module div(/*AUTOARG*/
   // Outputs
   o_quotient, o_reminder, o_done,
   // Inputs
   clk, rst, i_load, i_a, i_b, i_sign
   );

   parameter width = 32;
   localparam counter_width = log2(width)+1;
   
   output logic [width-1:0] o_quotient;
   output logic [width-1:0] o_reminder;
   output logic 			o_done;
   
   input logic 				clk;
   input logic 				rst;
   input logic 				i_load;
   
   input logic [width-1:0] 	i_a, i_b;
   input logic				i_sign; // 1:signed 0:unsigned
   
   logic 					a_sign, b_sign;

   assign a_sign = i_sign & i_a[width-1];
   assign b_sign = i_sign & i_b[width-1];

   // ==================== control ====================
   logic [counter_width-1:0] calc_cnt;
   logic 					 calc_done;
   logic 					 state_init, state_calc;
   
   // calc_done sustained until the next valid calc
   assign calc_done = calc_cnt[counter_width-1];
   assign state_init = i_load & calc_done;
   assign state_calc = !calc_done;
   
   always_ff@(posedge clk)
	 begin
		if(rst)
		  calc_cnt[counter_width-1] <= 1'b1; // 
		else if(state_init)
		  calc_cnt <= '0;
		else if(state_calc)
		  calc_cnt <= calc_cnt + 1'b1;
	 end
   
   // ---------- shift regs of quotient ----------
   logic [width-1:0] 		quotient_regs;
   logic 					q_current;
   
   always_ff@(posedge clk)
   	 begin
   		if(state_init)
   		  quotient_regs <= i_a;	// load data (dividend), only one clk
   		else if(state_calc)		   // shift for many clks
   		  quotient_regs <= { quotient_regs[width-2:0], q_current };
   	 end
   
   // ---------- regs of reminder ----------
   logic [width-1:0] 		sub_result;
   logic [width-1:0] 		reminder_regs;
   
   always_ff@(posedge clk)
	 begin
		if(state_init)
		  reminder_regs <= a_sign ? '1 : '0;
		else if(state_calc)
		  reminder_regs <= sub_result; // calculating for many clks
	 end

   // ---------- regs for judge 0 only when dividend(i_a) is negative  ----------
   logic [width-2:0] judge_rest_0_mask;
   logic 			 is_rest_0;
   
   always_ff@(posedge clk)
	 begin
		if(state_init)
		  judge_rest_0_mask <= '1;	// init value, mask 
		else if(state_calc)
		  judge_rest_0_mask <= { judge_rest_0_mask[width-3:0], 1'b0 }; // shift in 0 to umask the invalid bits
	 end
   
   assign is_rest_0 = ~|(judge_rest_0_mask[width-2:0] & quotient_regs[width-2:0]);

   
   
   // ---------- subtraction with condition ----------
   
   logic [width-1:0] 	   minuend, subtrahend;
   logic 				   add_sub_ctrl;
   logic [width-1:0] 	   sum_diff_tmp, sum_diff;
   logic 				   carry_borrow, carry_borrow_n;
   
   always_ff@(posedge clk)
	 begin
		if(state_init)
		  begin
			 subtrahend <= i_b;
			 add_sub_ctrl <= a_sign ~^ b_sign;
		  end
	 end
   
   assign minuend = { reminder_regs[width-2:0], quotient_regs[width-1] };
   
   // -------------------- add/sub --------------------
   DW01_add #(.width(width)) U_add(
   								   .A(minuend ^ {width{add_sub_ctrl}}),
   								   .B(subtrahend),
   								   .CI(1'b0),
   								   .SUM(sum_diff_tmp),
   								   .CO(carry_borrow) ); // infact, this Carry is for all mode
   
   assign {carry_borrow_n, sum_diff} = {carry_borrow, sum_diff_tmp} ^ {(width+1){add_sub_ctrl}}; // carry or inv of borrow
   // -------------------- add/sub --------------------
   
   assign is_sub_result_0 = (sum_diff == 0) && is_rest_0; // only needed when dividend is negative
   
   // assign q_current = a_sign ? (is_sub_result_0 | ~carry_borrow_n) : carry_borrow_n;
   // assign q_current = is_sub_result_0 | a_sign ^ carry_borrow_n;

   assign q_current = a_sign ? (sum_diff[width-1] ? 1'b1 : is_sub_result_0) : carry_borrow_n;
   

   assign sub_result = q_current ? sum_diff : minuend; // restore if current quotient bit invalid
   
   // ==================== output ====================
   assign o_quotient = (a_sign~^b_sign) ? quotient_regs : ~quotient_regs+1;
   assign o_reminder = reminder_regs;
   
   assign o_done = calc_done;
   
endmodule // div
